package com.mgq.juc.cas;

import lombok.Data;
import sun.misc.Unsafe;

import java.lang.reflect.Field;

/**
 * unsafe对象不能直接被调用,需要通过反射来获取
 * 演示利用unsafe对象安全的修改对象的属性值
 *
 *objectFieldOffset()方法
 * R大的回答
 *
 * sun.misc.Unsafe是JDK内部用的工具类。它通过暴露一些Java意义上说“不安全”的功能给Java层代码，
 * 来让JDK能够更多的使用Java代码来实现一些原本是平台相关的、需要使用native语言（例如C或C++）才可以实现的功能。该类不应该在JDK核心类库之外使用。
 *
 * JVM的实现可以自由选择如何实现Java对象的“布局”，也就是在内存里Java对象的各个部分放在哪里，
 * 包括对象的实例字段和一些元数据之类。sun.misc.Unsafe里关于对象字段访问的方法把对象布局抽象出来，
 * 它提供了objectFieldOffset()方法用于获取某个字段相对Java对象的“起始地址”的偏移量，
 * 也提供了getInt、getLong、getObject之类的方法可以使用前面获取的偏移量来访问某个Java对象的某个字段。
 *
 *
 */
public class TestUnsafe {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

        //
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        //字段是static的,不是对象的,所以传入null
        //get()方法返回的是这个字段的值
        Unsafe unsafe = (Unsafe) field.get(null);
        System.out.println(unsafe);

        long idOffset = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("id"));

        long nameField = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("name"));

        Teacher teacher = new Teacher();
        //参数一: 对象 参数二:字段偏移量 字段三:原始值 字段四:expect(需要修改的值)
        unsafe.compareAndSwapInt(teacher,idOffset,0,1);
        unsafe.compareAndSwapObject(teacher,nameField,null,"张三");
        //打印结果,最终会修改成功,利用CAS来完成了对对象的属性进行修改
        System.out.println(teacher);

        /*Field name = Teacher.class.getDeclaredField("name");
        name.setAccessible(true);
        Teacher teacher = new Teacher();
        System.out.println(teacher);
        Object o1 = name.get(teacher);
        System.out.println(o1);*/

    }
}

@Data
class Teacher {
    private String name;
    private int id;
}
